在物件導向程式設計裡有三個重要的觀念,封裝、繼承以及多型.
封裝可以把不想讓外部直接存取的屬性隱藏起來,也許只能透過 class 提供的 api 對封裝的屬性操作,但在 python 裡由於沒有真正的 private 所以雖然使用_名稱
或__名稱
封裝起來了,但還是有辦法存取得到.
當如果已經有一個 class 定義好一些屬性跟方法,如果想要使用但又跟原本的 class 有一點差異,就可以透過繼承
來獲得父類別的屬性和方法,然後再把要修改的方法覆寫
即可,該類別就成為了繼承父類別的子類別.
>>> class CusCounter:
... ratio = 5
... def count(self,num):
... return num * self.ratio + 1
...
想使用 CusCounter 的 count 方法,但 ratio 想要換掉,所以透過下面方式繼承
CusCounter 以及定義一個一樣名稱的 ratio覆寫
掉父類別的屬性.
>>> class MyCounter(CusCounter):
... ratio = 8
...
>>> counter = MyCounter()
>>> counter.count(3)
25
當然也可以覆寫
掉父類別的方法.
>>> class MyCounter(CusCounter):
... ratio = 8
... def count(self,num):
... return num * self.ratio + 5
...
>>> counter = MyCounter()
>>> counter.count(3)
29
可以透過super()
來呼叫父類別的方法.
>>> class MyCounter(CusCounter):
... ratio = 8
... def my_cus_count(self,num):
... return super().count(num)
...
>>> counter = MyCounter()
>>> counter.count(3)
25
>>> counter.my_cus_count(3)
25
可以透過__bases__
來查看某類別的父類別.
>>> MyCounter.__bases__
(<class '__main__.CusCounter'>,)
>>> CusCounter.__bases__
(<class 'object'>,)
isinstance 可以檢查參數一的 instance 是不是屬於第二個參數的 class.
>>> isinstance(counter,MyCounter)
True
>>> isinstance(counter,CusCounter)
True
issubclass 可以檢查第一個參數的 class 是不是第二個參數的 subclass.
>>> issubclass(MyCounter,CusCounter)
True
>>> issubclass(CusCounter,MyCounter)
False
當有已經定義好的一個 class,如果想在定義一個跟它相同行類型
的類別,但有一點點差異,可以透過繼承賦予子類別屬於父類別的 type.比如說已經有動物這 class,接著可以定義一個狗的類別繼承動物,而狗又分為很多品種,杜賓狗、吉娃娃、柴犬等不同類別又可以繼承狗這個類別,所以這些不同種類的狗都是屬於狗也屬於動物.當在使用繼承
而得到父類別的屬性跟方法時,再加上型態的思考,父子類別是否屬於同型態的設計,而達到了多型
的概念.
>>> class Animal:
... def move(self):
... print('Animal move...')
...
>>> class Dog(Animal):
... def move(self):
... print('Dog run...')
...
>>> class Chihuahua(Dog):
... def move(self):
... print('Chihuahua run...')
...
>>> class Doberman(Dog):
... def move(self):
... print('Doberman run...')
...
這時候定義一個 function,function 會使用帶入參數 animal 的 move() function.
>>> def moving(animal):
... animal.move()
...
該 function 會根據帶入的物件不同顯示結果,這也是多型的好處.
>>> moving(Dog())
Dog run...
>>> moving(Animal())
Animal move...
>>> moving(Doberman())
Doberman run...
如果帶入的物件沒有 move 這 function 就會出錯.
class Tree:
... def growing(self):
... print('Tree is growing...')
...
>>> moving(Tree())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in moving
AttributeError: 'Tree' object has no attribute 'move'